package com.hulk.hyena.framework.quartz.utils;

import com.hulk.hyena.common.constant.ScheduleConstants;
import com.hulk.hyena.common.exception.job.TaskException;
import com.hulk.hyena.project.monitor.job.domain.ScheduleJob;
import com.hulk.hyena.project.monitor.job.domain.Task;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 
 * 
 * @title: QuartzManager.java
 * @description: 计划任务管理
 *
 */
@Slf4j
@Service
public class QuartzManager {
	// private SchedulerFactoryBean schedulerFactoryBean
	// =SpringContextHolder.getBean(SchedulerFactoryBean.class);
	// @Autowired
	// @Qualifier("schedulerFactoryBean")
	// private SchedulerFactoryBean schedulerFactoryBean;
	@Autowired
	private Scheduler scheduler;

	/**
	 * 添加任务
	 * 
	 * @param job
	 * @throws SchedulerException
	 */
	
	public void addJob(ScheduleJob job) {
		try {
			// 创建jobDetail实例，绑定Job实现类
			// 指明job的名称，所在组的名称，以及绑定job类

			Class<? extends Job> jobClass = (Class<? extends Job>) (Class.forName(job.getBeanClass()).newInstance()
					.getClass());
			JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(job.getJobName(), job.getJobGroup())// 任务名称和组构成任务key
					.build();

			// 表达式调度构建器
			CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
			cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
			// 定义调度触发规则
			// 使用cornTrigger规则
			Trigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())// 触发器key
					.startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
					.withSchedule(cronScheduleBuilder).startNow().build();

			// 放入参数，运行时的方法可以获取
			//jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

			// 把作业和触发器注册到任务调度中
			scheduler.scheduleJob(jobDetail, trigger);
			// 启动
			if (!scheduler.isShutdown()) {
				scheduler.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("",e);
			throw new TaskException(e);
		}
	}
	/**
	 * 添加任务
	 *
	 * @param job
	 * @throws SchedulerException
	 */

	public void updateJob(ScheduleJob job) {
		try {
			// 创建jobDetail实例，绑定Job实现类
			// 指明job的名称，所在组的名称，以及绑定job类

			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());

			// 表达式调度构建器
			CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
			cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);

			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

			// 按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();

			// 参数
			//trigger.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

			scheduler.rescheduleJob(triggerKey, trigger);


			// 启动
			if (!scheduler.isShutdown()) {
				scheduler.start();
			}
		} catch (SchedulerException e) {
			throw new TaskException(e);
		}
	}

//	public void addJob(ScheduleJob job) throws SchedulerException {
//		if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
//			return;
//		}
//
//		TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
//
//		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//
//		// 不存在，创建一个
//
//		if (null == trigger) {
//			Class<? extends Job> clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent())
//					? QuartzJobFactory.class
//					: QuartzJobFactoryDisallowConcurrentExecution.class;
//
//			JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();
//
//			jobDetail.getJobDataMap().put("scheduleJob", job);
//
//			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
//
//			trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
//					.withSchedule(scheduleBuilder).build();
//
//			scheduler.scheduleJob(jobDetail, trigger);
//		} else {
//			// Trigger已存在，那么更新相应的定时设置
//
//			CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
//
//			// 按新的cronExpression表达式重新构建trigger
//
//			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//
//			// 按新的trigger重新设置job执行
//
//			scheduler.rescheduleJob(triggerKey, trigger);
//		}
//	}

	/**
	 * 获取所有计划中的任务列表
	 * 
	 * @return
	 * @throws SchedulerException
	 */
	public List<ScheduleJob> getAllJob(){
		try {
			GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
			Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
			List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
			for (JobKey jobKey : jobKeys) {
				List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
				for (Trigger trigger : triggers) {
					ScheduleJob job = new ScheduleJob();
					job.setJobName(jobKey.getName());
					job.setJobGroup(jobKey.getGroup());
					job.setDescription("触发器:" + trigger.getKey());
					Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
					job.setJobStatus(triggerState.name());
					if (trigger instanceof CronTrigger) {
						CronTrigger cronTrigger = (CronTrigger) trigger;
						String cronExpression = cronTrigger.getCronExpression();
						job.setCronExpression(cronExpression);
					}
					jobList.add(job);
				}
			}
			return jobList;
		} catch (SchedulerException e) {
			throw new TaskException(e);
		}
	}

	/**
	 * 所有正在运行的job
	 * 
	 * @return
	 * @throws SchedulerException
	 */
	public List<ScheduleJob> getRunningJob()  {
		try {
			List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
			List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(executingJobs.size());
			for (JobExecutionContext executingJob : executingJobs) {
				ScheduleJob job = new ScheduleJob();
				JobDetail jobDetail = executingJob.getJobDetail();
				JobKey jobKey = jobDetail.getKey();
				Trigger trigger = executingJob.getTrigger();
				job.setJobName(jobKey.getName());
				job.setJobGroup(jobKey.getGroup());
				job.setDescription("触发器:" + trigger.getKey());
				Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
				job.setJobStatus(triggerState.name());
				if (trigger instanceof CronTrigger) {
					CronTrigger cronTrigger = (CronTrigger) trigger;
					String cronExpression = cronTrigger.getCronExpression();
					job.setCronExpression(cronExpression);
				}
				jobList.add(job);
			}
			return jobList;
		} catch (SchedulerException e) {
			throw new TaskException(e);
		}
	}

	/**
	 * 暂停一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void pauseJob(ScheduleJob scheduleJob)  {
		try{
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.pauseJob(jobKey);
	} catch (SchedulerException e) {
		throw new TaskException(e);
	}
	}

	/**
	 * 恢复一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void resumeJob(ScheduleJob scheduleJob)  {
		try {
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.resumeJob(jobKey);
		} catch (SchedulerException e) {
			throw new TaskException(e);
		}
	}

	/**
	 * 删除一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void deleteJob(ScheduleJob scheduleJob)  {
		try {
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.deleteJob(jobKey);
		} catch (SchedulerException e) {
			throw new TaskException(e);
		}

	}

	/**
	 * 立即执行job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void runAJobNow(ScheduleJob scheduleJob) {
		try {
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.triggerJob(jobKey);
		} catch (SchedulerException e) {
			throw new TaskException(e);
		}
	}

	/**
	 * 获取jobKey
	 */
	public static JobKey getJobKey(Long jobId)
	{
		return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId);
	}
	/**
	 * 立即执行job
	 *
	 * @param
	 * @throws SchedulerException
	 */
	public int runNow(Scheduler scheduler, Task job) {
		int rows = 1;
		try
		{
			// 参数
			JobDataMap dataMap = new JobDataMap();
			dataMap.put(ScheduleConstants.TASK_PROPERTIES, job);

			scheduler.triggerJob(getJobKey(job.getId()), dataMap);
			rows = 0;
		}
		catch (SchedulerException e)
		{
			log.error("run 异常：", e);
		}
		return rows;
	}



	private static CronScheduleBuilder handleCronScheduleMisfirePolicy(ScheduleJob job, CronScheduleBuilder cb)
			throws TaskException
	{
		switch (job.getMisfirePolicy())
		{
			case ScheduleConstants.MISFIRE_DEFAULT:
				return cb;
			case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
				return cb.withMisfireHandlingInstructionIgnoreMisfires();
			case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
				return cb.withMisfireHandlingInstructionFireAndProceed();
			case ScheduleConstants.MISFIRE_DO_NOTHING:
				return cb.withMisfireHandlingInstructionDoNothing();
			default:
				throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() + "' cannot be used in cron schedule tasks", TaskException.Code.CONFIG_ERROR);
		}
	}
}